#ifndef MOMOque_UE_H
#define MOMOque_UE_H
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <string>
using std::tuple;
using std::mutex;


template< typename T>
class  AsyncQueue
{
public:
	AsyncQueue(unsigned int max_length) :max_length_(max_length)
	{
	}
	~AsyncQueue() {}
	inline void Enqueue(T c)
	{
		std::lock_guard<std::mutex> lock(lock_);
		if (que_.size() >= max_length_)
			throw std::exception("queue null");
		que_.push(c);
		cond_.notify_all();
	}
	inline T Dequeue()
	{
		T c;
		std::unique_lock<std::mutex> lock(lock_);
		while (que_.empty())
		{
			if (cond_.wait_for(lock, std::chrono::milliseconds{ 100 }) == std::cv_status::timeout)
			{
				break;
			}
		}
		if (que_.empty())
		{
			throw std::exception("queue full");
		}
		c = que_.front();
		que_.pop();
		return c;
	}
	inline T Peek()
	{
		T c;
		std::unique_lock<std::mutex> lock(lock_);
		while (que_.empty())
		{
			if (cond_.wait_for(lock, std::chrono::milliseconds{ 100 }) == std::cv_status::timeout)
			{
				break;
			}
		}
		if (que_.empty())
		{
			throw QueueNullException();
		}
		c = que_.front();
		return c;
	}
	inline void Clear()
	{
		while (que_.size() > 0)
		{
			que_.pop();
		}
	}
	inline unsigned int size()
	{
		return que_.size();
	}
private:
	std::queue<T> que_;
	std::mutex lock_;
	std::condition_variable cond_;
	AsyncQueue(const AsyncQueue&) = delete;
	unsigned int  max_length_;
};

#endif
